/*
    Copyright (C) 2004  Brano Kemen

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdio.h>
#include "coid/comm/commtypes.h"
#include "coid/comm/str.h"
#include "coid/comm/dir.h"

using namespace coid;


#ifndef SYSTYPE_MSVC

#include <dlfcn.h>
#include <signal.h>


static int Gloop = 0;

typedef int (* fn_coid_server_start)( int& port, int (*cancel_cbk)(int) );
typedef int (* fn_coid_server_stop)();
typedef int (* fn_coid_get_version)( charstr & );



const char * g_look_in[] = {".", "/usr/lib/coid", "/usr/local/lib/coid"};
int g_look_in_count = sizeof(g_look_in) / sizeof(char *);



////////////////////////////////////////////////////////////////////////////////
int cancel_request( int restart )
{
    if( restart )
    {
        //spawn another
    }

    Gloop = 0;
    return 0;
}

////////////////////////////////////////////////////////////////////////////////
int usage()
{
    printf( "Usage: coid [-v | --version] [-p port] [-l server_library] [config_directory]\n" );
    return 1;
}

////////////////////////////////////////////////////////////////////////////////
int main( int argc, char* argv[] )
{
    int port = 0;
    charstr working_dir;
    const char * lib_name = NULL;
    charstr tmp;
	bool bprint_version = false;
	
	directory::get_cwd(working_dir);

    for( int i = 1; i < argc; i++ ) {
        if( argv[i][0] == '-' ) {
            if( argv[i][1] == '-' ) {
				if( strcmp(argv[i] + 2, "version") == 0 )
					bprint_version = true;
				else if( strcmp(argv[i] + 2, "help") == 0 )
					return usage();
			}
            else if( argv[i][1] == 'v' ) bprint_version = true;
            else if( argv[i][1] == 'l' ) {
                i++;
                if( i < argc ) lib_name = argv[i];
                else {
                    printf( "option -l: server library name missing\n" );
                    return 5;
                }
            }
            else if( argv[i][1] == 'p' ) {
                i++;
                if( i < argc ) port = atol( argv[i] );
            }
        }
        else {
            if( ! directory::is_valid_directory(argv[i]) ) {
                printf( "Invalid directory: '%s'\n", argv[i] ); 
                return usage();
            }
            else working_dir = argv[i];
        }
    }
    if( !port ) port = 55099;

    sysDynamicLibrary server_lib;
    const char ** p = g_look_in;
    bool bfound = false;
    if( lib_name ) {
        tmp = lib_name;      /// for error messages
        server_lib.open( lib_name );
    }
    else {
        directory::get_ped(tmp);
        tmp += "libcoidserver.so";
        
        if( directory::is_valid_file(tmp) ) {
            bfound = true;
            server_lib.open( tmp.c_str() );
        }
        else {
            for( int i=0; i<g_look_in_count; i++, p++ ) {
                tmp = *p; tmp += "/libcoidserver.so";
                if( directory::is_valid_file(tmp) ) {
                    bfound = true;
                    server_lib.open( tmp.c_str() );
                    break;
                }
            }
        }
    }

    if( !server_lib.is_valid() ) {
        if( bfound ) printf( "Cannot open server library %s\n", tmp.ptr() );
        else printf( "Cannot find server library\n" );
        return 2;
    }
    printf( "Using server library   '%s'\n", tmp.ptr() ); 



	void * fnc0 = server_lib.getFuncAddress( "coid_get_version" );
	if( ! fnc0 ) {
		const char * err = dlerror();
		if( err ) printf( "%s\n", err );
		else printf( "Error loading server library %s\n", tmp.ptr() );
		return 3;
	}
	charstr ver;
	fn_coid_get_version coid_get_version = (fn_coid_get_version) fnc0;
	coid_get_version( ver );
	printf( "Server version:   %s\n", ver.ptr() );

	if( bprint_version )
		return 0;


    void * fnc1 = server_lib.getFuncAddress( "coid_server_start" );
    if( ! fnc1 ) {
        const char * err = dlerror();
        if( err ) printf( "%s\n", err );
        else printf( "Error loading server library %s\n", tmp.ptr() );
        return 3;
    }

    void * fnc2 = server_lib.getFuncAddress( "coid_server_stop" );
    if( ! fnc2 ) {
        const char * err = dlerror();
        if( err ) printf( "%s\n", err );
        else printf( "Error loading server library %s\n", tmp.ptr() );
        return 3;
    }

    directory::treat_trailing_separator(working_dir, false);
    if( chdir(working_dir.c_str()) != 0 ) {
        printf( "Error changing directory to %s\n", working_dir.c_str() );
        return 4;
    }

    fn_coid_server_start coid_server_start = (fn_coid_server_start) fnc1;
    fn_coid_server_stop coid_server_stop = (fn_coid_server_stop) fnc2;

#ifndef _DEBUG
    sigset_t signal_set;
    sigemptyset(&signal_set);
    sigaddset(&signal_set, SIGINT);
    pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
#endif

    if( 0 == coid_server_start(port, &cancel_request) ) {
        Gloop = 1;
        while( Gloop )
        {
#ifndef _DEBUG
            coid::sysSleep(1);

            int sig_number;
            int err = sigwait(&signal_set, &sig_number);
            if(err || sig_number == SIGINT) {
                break;
            }
#else
            char buf[32];
            fgets(buf, 32, stdin);

            if(0 == strcmp(buf,"exit"))
                break;
#endif
        }

        printf( "Stopping the server ... \n" );
        coid_server_stop();
    }

    return 0;
}

#endif //SYSTYPE_MSVC
